package mx.db;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import net.sf.json.JSONObject;

@SuppressWarnings("rawtypes")
public class MXDBS {
	
	private String xmlPath="Database.xml";
	private String localDBName="";
	private Document doc=null;
	private Element rootNode=null;
	
	public MXDBS(){}
	
	public MXDBS(String xmlPath){
		this.xmlPath=xmlPath;
	}
	
	public void use(String DBName){
		this.localDBName=DBName;
		System.out.println("use "+DBName+" !");
	}
	
	public void newDB(String name) throws Exception {
		readXML();
		Iterator it=this.rootNode.elementIterator();
		while(it.hasNext()){
			Element e=(Element)it.next();
			String str=e.attribute("name").getValue();
			if(str.equals(name)){
				System.out.println("There is an Database named "+name+" existed now!");
				use(name);
				return;
			}
		}
		addElement(rootNode, "DB").addAttribute("name", name);
		writeXML();
		System.out.println("Add a new Database named "+name+" !");
		use(name);
	}
	
	public void newCollection(String collectionName) throws Exception{
		readXML();
		Iterator it=this.rootNode.elementIterator();
		while(it.hasNext()){
			Element e=(Element)it.next();
			String str=e.attribute("name").getValue();
			if(str.equals(this.localDBName)){
				addElement(e, "Collection").addAttribute("name", collectionName);
				writeXML();
				System.out.println("Add a new table named "+collectionName+" !");
				return;
			}
		}
	}
	
	public void insert(String collectionName,Object obj) throws Exception{
		readXML();
		Iterator it=this.rootNode.elementIterator();
		while(it.hasNext()){
			Element e=(Element)it.next();
			String str=e.attribute("name").getValue();
			if(str.equals(this.localDBName)){
				Iterator collections=e.elementIterator();
				while(collections.hasNext()){
					Element collection=(Element)collections.next();
					if(collectionName.equals(collection.attributeValue("name"))){
						Element record=collection.addElement("Record");
						UUID uuid = UUID.randomUUID();
						record.addAttribute("id", uuid.toString());
						JSONObject jsonObj = JSONObject.fromObject(obj);
						Iterator keys=jsonObj.keys();
						while(keys.hasNext()){
							String key=(String)keys.next();
							record.addAttribute(key, jsonObj.getString(key));
						}
					}
				}
				writeXML();
				System.out.println("Insert record successfully!");
				return;
			}
		}
	}
	
	public void delete(String collectionName,String jsonCondition) throws Exception{
		int affectNum=0;
		readXML();
		List<Element> list=getRecordsByJson(collectionName, jsonCondition);
		for(Element elem:list){
			elem.getParent().remove(elem);
			affectNum+=1;
		}
		writeXML();
		System.out.println("Delete "+affectNum+" records!");
	}
	
	/**
	 * 根据条件更新相应的数据项
	 * @param collectionName
	 * @param condition
	 * @param obj
	 * @throws Exception 
	 */
	@SuppressWarnings("unchecked")
	public void update(String collectionName,String jsonCondition,String jsonData) throws Exception{
		readXML();
		List<Element> list=getRecordsByJson(collectionName, jsonCondition);
		Set<Entry<String,Object>> dataSet=parseJSON(jsonData);
		for(Element elem:list){
			for(Iterator iter = dataSet.iterator(); iter.hasNext();){
				Entry data = (Entry)iter.next();
				List<Attribute> attrList=elem.attributes();
				int i=attrList.size();
				for(Attribute attr:attrList){
					i=i-1;
					if(data.getKey().equals(attr.getName())){
						attr.setValue((String) data.getValue());
						continue;
					}else if(i==0){
						elem.addAttribute((String)data.getKey(), (String)data.getValue());
					}
				}
			}
		}
		writeXML();
		System.out.println("Update record successfully!");
	}
	
	@SuppressWarnings("unchecked")
	public void find(String collectionName,String jsonCondition) throws Exception{
		List<Element> list=getRecordsByJson(collectionName, jsonCondition);
		for(Element e:list){
			List<Attribute> attrList=e.attributes();
			StringBuffer sb=new StringBuffer();
			sb.append("[|");
			for(Attribute attr:attrList){
				sb.append(((String)attr.getName())+":"+((String)attr.getValue()));
				sb.append("|");
			}
			sb.append("]");
			System.out.println(sb);
		}
	}
	
	private void readXML() throws Exception{
		SAXReader reader = new SAXReader();
		this.doc = reader.read(new File(xmlPath));
		this.rootNode = doc.getRootElement();
	}
	
	private void writeXML() throws Exception{
		// 紧凑的格式  
        // OutputFormat format = OutputFormat.createCompactFormat();  
        // 排版缩进的格式  
        OutputFormat format = OutputFormat.createPrettyPrint();  
        // 设置编码  
        format.setEncoding("UTF-8");
        XMLWriter writer = new XMLWriter(new OutputStreamWriter(  
                new FileOutputStream(new File(xmlPath)), "UTF-8"), format);  
        writer.write(this.doc);  
        writer.flush();  
        writer.close();
	}
	
	private Element addElement(Element target,String ename){
    	return target.addElement(ename);
    }
	
	/**
	 * 根据json字符串查询条件搜索出符合查询条件的表中数据项
	 * @param collectionName 要搜索的表的名称
	 * @param json 搜索条件
	 * @return 搜索的结果集
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	private List<Element> getRecordsByJson(String collectionName,String jsonCondition) throws Exception{
		List<Element> resList=new ArrayList();
		Set<Entry<String,Object>> entrySet=parseJSON(jsonCondition);
		//初始化一个条件集合的数目，当一个条件满足之后就减去1，所有条件都满足的时候conds=0.
		int conds=-1;
		readXML();
		Iterator it=this.rootNode.elementIterator();
		while(it.hasNext()){
			Element e=(Element)it.next();
			String str=e.attribute("name").getValue();
			if(str.equals(this.localDBName)){
				Iterator collections=e.elementIterator();
				while(collections.hasNext()){
					Element collection=(Element)collections.next();
					if(collectionName.equals(collection.attributeValue("name"))){
						Iterator records=collection.elementIterator();
						while(records.hasNext()){
							Element record=(Element)records.next();
							conds=entrySet.size();
							for(Iterator<Entry<String, Object>> iter = entrySet.iterator(); iter.hasNext();){
								Entry<String, Object> entry = iter.next();
								if(record.attribute(entry.getKey()).getValue().equals(entry.getValue())){
									conds=conds-1;
								}
							}
							if(conds==0){
								resList.add(record);
							}
						}
					}
				}
			}
		}
		return resList;
	}
	
	@SuppressWarnings("unchecked")
	public Set<Entry<String,Object>> parseJSON(String jsonString){
		Map<String,Object> jsonMap=JSONObject.fromObject(jsonString);
		Set<Entry<String,Object>> entrySet=jsonMap.entrySet();
		return entrySet;
	}
}
